﻿using LiveCharts.Wpf;
using LiveCharts;
using Sunny.UI;
using System.Configuration;
using File = System.IO.File;
using Excel = Microsoft.Office.Interop.Excel;
using MessageBox = System.Windows.Forms.MessageBox;
using System.Net.Sockets;
using System.Net;
using System;
using System.Windows.Forms;
using System.Threading;

namespace FZRD
{
    public partial class Page2 : UIPage
    {
        //监听线程
        //[DisallowNull]
        public static Thread receiveThread2;

        //X轴值数量初始值
        private long xCount = 500;

        private long xTimes = 0;

        //通道初始值
        private int channelIndex = 0;

        private bool isSaveWaveLength = false;

        private string spectrumFilePath = "D:\\聚芯光纤\\";

        private string spectrumFileName = "光谱数据";

        private string spectrumFileNameDate = "";

        //[DisallowNull]
        private Excel.Application excelApp;

        //[DisallowNull]
        private Excel._Workbook workbook;


        public Page2()
        {

            InitializeComponent();
            InitChartConfig(0);

            #region  多Y轴曲线
            //将自定义类型MeasureModel映射到曲线坐标点
            var mapper = LiveCharts.Configurations.Mappers.Xy<DataPoint>()
              .X(model => model.Times)    //使用 Time.作为X轴的标签
              .Y(model => model.Value);  //使用Value 作为Y轴的值

            //全局保存映射器
            Charting.For<DataPoint>(mapper);
            #endregion

            this.channelIndex = Convert.ToInt32(ConfigurationManager.AppSettings["cbSpectrumChannelSellect"]);
            this.cbSpectrumChannelSellect.SelectedIndex = this.channelIndex;
            this.cbSaveSpectrum.Checked = Convert.ToBoolean(ConfigurationManager.AppSettings["cbSaveSpectrum"]);
            this.spectrumFilePath = ConfigurationManager.AppSettings["tbSpectrumFilePath"];
            this.spectrumFileName = ConfigurationManager.AppSettings["spectrumFileName"];
            this.tbSpectrumFilePath.Text = this.spectrumFilePath;

            //开启接收消息线程
            //receiveThread2 = new Thread(ReciveMessage);
            //receiveThread2.Start();

            //excelApp = new Excel.Application();

            //CreateExcelDataFile();

        }

        //窗口关闭事件委托，在窗口关闭事件前处理
        private void Page2_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (receiveThread2 != null){
                receiveThread2.Interrupt();
            }

            if (this.isSaveWaveLength)
            {
                if (this.excelApp != null)
                {
                    this.excelApp.DisplayAlerts = false;
                    if (this.workbook != null)
                    {
                        this.workbook.Close(false);
                        this.workbook = null;
                    }
                    this.excelApp.Quit();
                    this.excelApp = null;
                }
            }
        }

        private void InitChartConfig(int channelID)
        {
            string title = "通道-" + (channelID + 1);
            // 假设你在非UI线程上
            if (OscChart.InvokeRequired)
            {
                OscChart.Invoke(new System.Action(() =>
                {
                    OscChart.Series.Add(new LineSeries
                    {
                        Title = title,
                        PointGeometry = DefaultGeometries.Circle,
                        PointGeometrySize = 15,
                        StrokeThickness = 4,
                        LineSmoothness = 0,
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        Values = InitChartValuesEmptyData(),
                        ScalesYAt = channelID
                    });
                    OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                    {
                        //Title = "时间",
                        FontSize = 12,
                        DisableAnimations = true,
                        Foreground = System.Windows.Media.Brushes.Black,
                        LabelFormatter = value => value.ToString(),
                        //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                        Separator = new Separator
                        {
                            Step = 1,
                            IsEnabled = true
                        },
                        MaxValue = this.xCount,
                        MinValue = 0
                    });
                    OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                    {
                        Title = "dBm",
                        FontSize = 12,
                        Foreground = System.Windows.Media.Brushes.DodgerBlue,
                        Position = AxisPosition.LeftBottom
                    });
                }));
            }
            else
            {
                OscChart.Series.Add(new LineSeries
                {
                    Title = title,
                    PointGeometry = DefaultGeometries.Circle,
                    PointGeometrySize = 15,
                    StrokeThickness = 4,
                    LineSmoothness = 0,
                    PointForeground = System.Windows.Media.Brushes.Blue,
                    Values = InitChartValuesEmptyData(),
                    ScalesYAt = channelID
                });
                OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                {
                    //Title = "时间",
                    FontSize = 12,
                    DisableAnimations = true,
                    Foreground = System.Windows.Media.Brushes.Black,
                    LabelFormatter = value => value.ToString(),
                    //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                    Separator = new Separator
                    {
                        Step = 1,
                        IsEnabled = true
                    },
                    MaxValue = this.xCount,
                    MinValue = 0
                });
                OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                {
                    Title = "dBm",
                    FontSize = 12,
                    Foreground = System.Windows.Media.Brushes.DodgerBlue,
                    Position = AxisPosition.LeftBottom
                });
            }
        }

        private ChartValues<DataPoint> InitChartValuesData()
        {
            ChartValues<DataPoint> chartValues = new ChartValues<DataPoint>();
            for (long i = 1; i <= this.xCount; i++)
            {
                chartValues.Add(new DataPoint(i, 1550.00001D));
            }
            this.xTimes = this.xCount;
            return chartValues;
        }

        private static ChartValues<DataPoint> InitChartValuesEmptyData()
        {
            ChartValues<DataPoint> chartValues = new ChartValues<DataPoint>();
            return chartValues;
        }

        private void cbSaveSpectrum_CheckedChanged(object sender, System.EventArgs e)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            AppSettingsSection app = config.AppSettings;
            app.Settings["cbSaveSpectrum"].Value = this.cbSaveSpectrum.Checked + "";
            config.Save(ConfigurationSaveMode.Modified);
        }

        private void cbSpectrumChannelSellect_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            if (this.channelIndex != this.cbSpectrumChannelSellect.SelectedIndex)
            {
                // 假设你在非UI线程上
                if (this.cbSpectrumChannelSellect.InvokeRequired)
                {
                   this.cbSpectrumChannelSellect.Invoke(new System.Action(() =>
                   {
                       this.channelIndex = this.cbSpectrumChannelSellect.SelectedIndex;
                   }));
                }
                else
                {
                // 直接进行操作，因为当前线程就是UI线程
                    this.channelIndex = this.cbSpectrumChannelSellect.SelectedIndex;
                }
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                AppSettingsSection app = config.AppSettings;
                app.Settings["cbSpectrumChannelSellect"].Value = this.cbSpectrumChannelSellect.SelectedIndex + "";
                config.Save(ConfigurationSaveMode.Modified);
            }
        }

        private void tbSpectrumFilePath_TextChanged(object sender, EventArgs e)
        {
            if (tbSpectrumFilePath.Text.Length > 0)
            {
                if (!this.spectrumFilePath.Equals(this.tbSpectrumFilePath.Text))
                {
                    this.spectrumFilePath = this.tbSpectrumFilePath.Text;
                    if (this.isSaveWaveLength)
                    {
                        if (this.excelApp != null)
                        {
                            this.excelApp.DisplayAlerts = false;
                            if (this.workbook != null)
                            {
                                this.workbook.Close(false);
                                this.workbook = null;
                            }
                            this.excelApp.Quit();
                            this.excelApp = null;
                        }
                        CreateExcelDataFile();
                    }
                    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                    AppSettingsSection app = config.AppSettings;
                    app.Settings["tbSpectrumFilePath"].Value = this.tbSpectrumFilePath.Text;
                    config.Save(ConfigurationSaveMode.Modified);
                }
            }
        }

        private void ibOpenFilePath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.ShowDialog();
            this.ibOpenFilePath.Text = folderBrowserDialog.SelectedPath; //获得选择的文件夹路径
        }

        private void btnReadSpectrum_Click(object sender, EventArgs e)
        {
            bool isOpenServerPort = MainForm.getOpenServerPort();
            if (!isOpenServerPort)
            {
                MessageBox.Show("请先打开服务端口！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            Socket serverSocket = MainForm.getServerSocket();
            if (serverSocket == null){
                return;
            }
            EndPoint endPoint = MainForm.getEndPoint();
            //停用按钮，防止多次点击
            this.btnReadSpectrum.Enabled = false;
            try
            {
                //如果不为空
                byte[] bmsg = [0x01, 0x16, (byte)this.channelIndex];
                if (bmsg != null)
                {
                    CreateExcelDataFile();

                    //开启接收消息线程
                    receiveThread2 = new Thread(ReciveMessage);
                    receiveThread2.Start();

                    //发送数据包
                    serverSocket.SendTo(bmsg, endPoint);
                }
                else
                {
                    MessageBox.Show("发送数据格式错误：" + bmsg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (SocketException es)
            {
                MessageBox.Show("发送数据报时出现异常：" + es.ErrorCode + "！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                //按钮启用
                btnReadSpectrum.Enabled = true;
            }
        }


        // 接收发送给本机IP对应端口号的数据报
        private void ReciveMessage()
        {
            Socket serverSocket = MainForm.getServerSocket();
            if (serverSocket == null){
                return;
            }
            try
            {
                while (MainForm.getOpenServerPort())
                {
                    //用来保存发送方的IP和端口号
                    EndPoint point = new IPEndPoint(IPAddress.Any, 0);
                    //消息缓存区申请
                    byte[] buffer = new byte[1024];
                    //接收数据报
                    int length = serverSocket.ReceiveFrom(buffer, ref point);
                    byte[] revBuf = new byte[length];
                    Buffer.BlockCopy(buffer, 0, revBuf, 0, length);
                    //显示在波形图里
                    this.ReciveSpectrumData(revBuf);
                }
            }
            catch (SocketException e)
            {
                //MessageBox.Show("接收发送给本机IP对应端口号的数据报错！" + e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                //if (serverSocket != null)
                //{
                //    if (serverSocket.Connected)
                //    {
                //        serverSocket.Disconnect(false);
                //    }
                //    serverSocket.Close();
                //    serverSocket.Dispose();
                //}
            }
        }

        private void ReciveSpectrumData(byte[] revData)
        {
            byte head = revData[0];
            byte cmd = revData[1];
            if (cmd == 0x02)
            {

            }
            else if (cmd == 0x04)
            {

            }
            else if (cmd == 0x06)
            {

            }
            else if (cmd == 0x07)
            {

            }
            else if (cmd == 0x08)
            {

            }
            else if (cmd == 0x0A)
            {

            }
            else if (cmd == 0x0C)
            {

            }
            else if (cmd == 0x14)
            {

            }
            else if (cmd == 0x16)
            {
                byte channelID = revData[2];
                byte packageCount = revData[3];
                int length = (revData.Length - 4) / 2;

                if (channelID == this.channelIndex)
                {
                    string[] values = new string[length + 2];
                    values[0] = channelID + 1 + "";
                    values[1] = packageCount + "";

                    for (int package = 0; package < length; package++)
                    {
                        this.xTimes++;
                        byte[] tempArray1 = new byte[2];

                        Buffer.BlockCopy(revData, 2 * package + 4, tempArray1, 0, 2);
                        uint valueL = tempArray1[0];
                        uint valueH = tempArray1[1];
                        double spectrum = (double)DivideAndRound((int)(valueL + valueH * 256), 10, 5);
                        values[package + 2] = spectrum + "";

                        int _count = OscChart.Series[0].Values.Count;
                        if (_count > this.xCount)
                        {
                            // 假设你在非UI线程上
                            if (OscChart.InvokeRequired)
                            {
                                OscChart.Invoke(new System.Action(() =>
                                {
                                    //只关心前面30个数据
                                    OscChart.Series[0].Values.RemoveAt(0);
                                    //添加y值，pointValue为波长数据
                                    var pointValue = new DataPoint(this.xTimes, spectrum);
                                    //更新纵坐标数据
                                    OscChart.Series[0].Values.Add(pointValue);
                                    //在这里进行UI相关的操作，例如修改OscChart的属性等
                                    OscChart.AxisX[0].MaxValue = this.xTimes;
                                    OscChart.AxisX[0].MinValue = this.xTimes - this.xCount;
                                    OscChart.Refresh();
                                }));
                            }
                            else
                            {
                                //只关心前面30个数据
                                OscChart.Series[0].Values.RemoveAt(0);
                                //添加y值，pointValue为波长数据
                                var pointValue = new DataPoint(this.xTimes, spectrum);
                                //更新纵坐标数据
                                OscChart.Series[0].Values.Add(pointValue);
                                // 直接进行操作，因为当前线程就是UI线程
                                OscChart.AxisX[0].MaxValue = this.xTimes;
                                OscChart.AxisX[0].MinValue = this.xTimes - this.xCount;
                                OscChart.Refresh();
                            }
                        }
                        else
                        {
                            // 假设你在非UI线程上
                            if (OscChart.InvokeRequired)
                            {
                                OscChart.Invoke(new System.Action(() =>
                                {
                                    //添加y值，pointValue为波长数据
                                    var pointValue = new DataPoint(this.xTimes, spectrum);
                                    //更新纵坐标数据
                                    OscChart.Series[0].Values.Add(pointValue);
                                    //在这里进行UI相关的操作，例如修改OscChart的属性等
                                    OscChart.AxisX[0].MaxValue = this.xTimes;
                                    OscChart.AxisX[0].MinValue = 0;
                                    OscChart.Refresh();
                                }));
                            }
                            else
                            {
                                //添加y值，pointValue为波长数据
                                var pointValue = new DataPoint(this.xTimes, spectrum);
                                //更新纵坐标数据
                                OscChart.Series[0].Values.Add(pointValue);
                                // 直接进行操作，因为当前线程就是UI线程
                                OscChart.AxisX[0].MaxValue = this.xTimes;
                                OscChart.AxisX[0].MinValue = 0;
                                OscChart.Refresh();
                            }
                        }
                    }
                    //保存到Excel文件
                    SaveDataToExcel(values);
                }
            }
            else if (cmd == 0x17)
            {

            }
            else if (cmd == 0x24)
            {

            }
            else if (cmd == 0x26)
            {

            }
            else if (cmd == 0x2E)
            {

            }
            else if (cmd == 0x30)
            {

            }
            else if (cmd == 0x32)
            {

            }
            else if (cmd == 0x34)
            {

            }
            else
            {

            }

        }

        private void CreateExcelDataFile()
        {
            // 创建Excel应用程序实例
            this.excelApp = new Excel.Application();
            if (this.excelApp == null)
            {
                MessageBox.Show("无法创建excel对象，请确认excel环境是否正常");
                return;

            }
            this.excelApp.Visible = false;
            this.excelApp.UserControl = true;
            this.excelApp.DisplayAlerts = false;

            DateTime dt = DateTime.Now;
            //int hour = dt.Hour;
            //int min = dt.Minute;
            //int hh = hour * 60 + min / 1;
            string date = dt.Year.ToString("D4") + dt.Month.ToString("D2") + dt.Day.ToString("D2");
            string filePath;
            if (this.spectrumFilePath.IsNullOrEmpty())
            {
                filePath = AppDomain.CurrentDomain.BaseDirectory + this.spectrumFileName + @"-" + date + @".xlsx";
            }
            else
            {
                filePath = this.spectrumFilePath + this.spectrumFileName + @"-" + date + @".xlsx";
            }
            Excel.Workbooks workbooks = this.excelApp.Workbooks;
            try
            {
                if (!File.Exists(filePath))
                {
                    File.Copy(AppDomain.CurrentDomain.BaseDirectory + this.spectrumFileName + @".xlsx", filePath, true);
                }
                workbook = workbooks.Add(filePath); //加载模板
            }
            catch (Exception ex)
            {
                bool isUnlocked = FileUnlocker.UnlockFile(filePath);
                if (isUnlocked)
                {
                    workbook = workbooks.Add(filePath); //加载模板
                }
                else
                {
                    MessageBox.Show("存储 Excel 文件时出错,文件可能正被打开！\n" + ex.Message);
                    return;
                }
            }
            this.spectrumFileNameDate = date;
        }

        //数据保存到excel
        public void SaveDataToExcel(string[] data)
        {
            if (!this.cbSaveSpectrum.Checked)
            {
                return;
            }
            if (this.excelApp == null)
            {
                MessageBox.Show("无法创建 Excel 对象，请确认 Excel 环境是否正常");
                return;

            }
            if (this.workbook == null)
            {
                MessageBox.Show("无法打开 Workbook 对象，请确认 Excel 文件是否正常");
                return;

            }
            DateTime dt = DateTime.Now;
            int hour = dt.Hour;
            int min = dt.Minute;
            int sec = dt.Second;
            int msec = dt.Millisecond;
            //int hh = hour * 60 + min / 1;
            string date = dt.Year.ToString("D4") + dt.Month.ToString("D2") + dt.Day.ToString("D2");
            string filePath = AppDomain.CurrentDomain.BaseDirectory + spectrumFileName + @"-" + date + @".xlsx";
            if (!this.spectrumFileNameDate.Equals(date))
            {
                this.workbook.Close(false);
                this.workbook = null;
                //excelApp.Quit();
                //excelApp = null;
                Excel.Workbooks workbooks = this.excelApp.Workbooks;
                if (!File.Exists(filePath))
                {
                    File.Copy(AppDomain.CurrentDomain.BaseDirectory + spectrumFileName + @".xlsx", filePath, true);
                }
                this.workbook = workbooks.Add(filePath); //加载模板
                this.spectrumFileNameDate = date;
            }

            Excel.Sheets sheets = this.workbook.Sheets;
            Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1); //第一个工作薄。
            if (worksheet == null)
            {
                MessageBox.Show("无法打开 Worksheet 对象，请确认 Excel 文件是否正常");
                return; //工作薄中没有工作表.
            }
            worksheet.Name = date;

            int columnIndex = 1; // A列的索引是1
            int columnCount = CountColumnValues(worksheet, columnIndex);
            //写入标题
            worksheet.Cells[columnCount + 1, 1] = hour.ToString() + ":" + min.ToString() + ":" + sec.ToString() + ":" + msec.ToString();

            //写入数值
            for (int i = 0; i < data.Length; i++)
            {
                worksheet.Cells[columnCount + 1, i + 2] = data[i];
            }
            worksheet.Columns.EntireColumn.AutoFit();//列宽自适应

            try
            {
                this.workbook.Saved = true;
                this.workbook.SaveAs(filePath);
            }
            catch (Exception ex)
            {
                bool isUnlocked = FileUnlocker.UnlockFile(filePath);
                if (isUnlocked)
                {
                    this.workbook.SaveAs(filePath);
                }
                else
                {
                    MessageBox.Show("存储 Excel 文件时出错,文件可能正被打开！\n" + ex.Message);
                    return;
                }
            }
        }

        public static int CountColumnValues(Excel.Worksheet worksheet, int columnIndex)
        {
            int valueCount = 0;
            Excel.Range usedRange = worksheet.UsedRange;

            // 获取列的范围
            Excel.Range columnRange = (Excel.Range)worksheet.Columns[columnIndex];
            int lastRow = columnRange.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row;

            // 遍历列中的所有单元格
            for (int row = 1; row <= lastRow; row++)
            {
                Excel.Range cell = (Excel.Range)worksheet.Cells[row, columnIndex];
                if (cell.Value2 != null && !cell.Value2.ToString().Trim().Equals(""))
                {
                    valueCount++;
                }
            }

            System.Runtime.InteropServices.Marshal.ReleaseComObject(columnRange);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(usedRange);

            return valueCount;
        }

        public static decimal DivideAndRound(decimal dividend, decimal divisor, int decimalPlaces)
        {
            if (divisor == 0)
            {
                throw new DivideByZeroException();
            }
            decimal result = dividend / divisor;
            return Math.Round(result, decimalPlaces);
        }
    }
}